package cn.yeyiu.netonlinevideo.util;


import android.util.Base64;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;

import java.security.Security;
import java.util.Scanner;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * AES加解密工具类
 * <p>
 * Date 2020/12/5-14:11
 */
public class AESUtil {
    /**
     * 密钥算法 AES
     */
    private static final String KEY_ALGORITHM = "AES";

    /**
     * 加解密算法/工作模式/填充方式
     * java支持PKCS5Padding、不支持PKCS7Padding
     * Bouncy Castle支持PKCS7Padding填充方式
     */
    private static final String CIPHER_ALGORITHM = "AES/ECB/PKCS7Padding";

    public static final String AL_ECB_5P = "AES/ECB/PKCS5Padding";
    public static final String AL_ECB_7P = "AES/ECB/PKCS7Padding";
    public static final String AL_CBC_5P = "AES/CBC/PKCS5Padding";

    /**
     * 偏移量，CBC模式需要
     * 与其他语言平台使用的需一致才能通用加解密
     */
    private static final String IV = "0000000000000000";

    public static final String ENCODING = "UTF-8";

    static {
        // 是PKCS7Padding填充方式，则需要添加Bouncy Castle支持
        Security.addProvider(new BouncyCastleProvider());
    }

    /**
     * AES加密方法
     *
     * @param source   原文
     * @param password 加密密钥
     * @return 密文
     */
    public static String encrypt(String source, String password) {
        String encryptText = "";
        try {
            byte[] sourceBytes = source.getBytes(ENCODING);
            byte[] passwordBytes = password.getBytes(ENCODING);
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
//            IvParameterSpec iv = new IvParameterSpec(IV.getBytes(ENCODING));
            cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(passwordBytes, KEY_ALGORITHM));
            byte[] encryptBytes = cipher.doFinal(sourceBytes);
            encryptText = Base64.encodeToString(encryptBytes, Base64.DEFAULT);

        } catch (Exception e) {
            return "";
        }
        return encryptText;
    }

    /**
     * AES解密方法
     *
     * @param encryptText 密文
     * @param password    密码
     * @return 原文
     */
    public static String decrypt(String encryptText, String password) {
        String decryptText;
        try {
            byte[] sourceBytes = Base64.decode(encryptText, Base64.DEFAULT);
            byte[] passwordBytes = password.getBytes(ENCODING);
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
//            IvParameterSpec iv = new IvParameterSpec(IV.getBytes(ENCODING));
            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(passwordBytes, KEY_ALGORITHM));
            byte[] decryptBytes = cipher.doFinal(sourceBytes);
            decryptText = new String(decryptBytes, ENCODING);
        } catch (Exception e) {
            return "";
        }
        return decryptText;
    }

    /**
     * AES通用方法
     *
     * @param source     密文
     * @param password   密码
     * @param ivStr      偏移
     * @param algorithm  算法
     * @param cryptModel 加密 or 解密
     * @return 原文
     */
    public static String crypt(String source, String password, String ivStr,
                               String algorithm,
                               boolean isSourceBase64,
                               boolean isResultBase64,
                               int cryptModel) {
        String encryptText = "";
        try {
            byte[] sourceBytes;
            if (cryptModel == Cipher.ENCRYPT_MODE) {
                sourceBytes = source.getBytes(ENCODING);
            } else if (isSourceBase64) {// 解密字符串有base64 和 hex 格式
                sourceBytes = Base64.decode(source, Base64.DEFAULT);
            } else {
                sourceBytes = Hex.decode(source);
            }

            byte[] passwordBytes = password.getBytes(ENCODING);
            Cipher cipher = Cipher.getInstance(algorithm);

            cipher.init(cryptModel,
                    new SecretKeySpec(passwordBytes, KEY_ALGORITHM),
                    new IvParameterSpec(ivStr.getBytes(ENCODING)));

            byte[] cryptBytes = cipher.doFinal(sourceBytes);
            if (cryptModel == Cipher.DECRYPT_MODE) {
                encryptText = new String(cryptBytes, ENCODING);
            } else if (isResultBase64) {// 加密字符串有base64 和 hex 格式
                encryptText = Base64.encodeToString(cryptBytes, Base64.DEFAULT);
            } else {
                encryptText = new String(Hex.encode(cryptBytes), ENCODING);
            }

        } catch (Exception e) {
            return "";
        }
        return encryptText;
    }

    public static String encryptHex(String source, String password, String ivStr, String algorithm) {
        return crypt(source, password, ivStr, algorithm, false, false, Cipher.ENCRYPT_MODE);
    }

    public static String decryptHex(String source, String password, String ivStr, String algorithm) {
        return crypt(source, password, ivStr, algorithm, false, false, Cipher.DECRYPT_MODE);
    }

    // AES密码长度只能为16/24/32个字符长度
    public static String checkPassword(Scanner scanner, String pwd) {
        while (pwd == null || "".equals(pwd) || pwd.length() < 16) {
            System.out.print("密码长度需为16个或以上长度的字符，请重新输入：");
            pwd = scanner.next().trim();
        }
        if (pwd.length() < 32) {
            int lessNum = 32 - pwd.length();
            StringBuilder builder = new StringBuilder(32);
            builder.append(pwd);
            for (int i = 0; i < lessNum; i++) {
                builder.append("a");
            }
            pwd = builder.toString();
        }
        if (pwd.length() > 32) {
            pwd = pwd.substring(0, 32);
        }
        return pwd;
    }
}